
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>

#include <vector>
#include <set>
#include <map>

using namespace std;


const char* g_text_filename = "ssq2010.txt";

struct  Issue
{
    enum {
        N_ISSUE_HOT = 5,
    };

public  :
    string  date;
    int     id;
    int     r[6];
    int     b;

    int     ac;

    // hotness in last N issues
    typedef map< int, set< int > >  red_history_contrib_set_type;
    typedef red_history_contrib_set_type::iterator  red_history_contrib_set_iterator_type;

    red_history_contrib_set_type    red_history_contrib_set;
    int     red_history_contrib[ N_ISSUE_HOT ];
    

public  :
    Issue() 
    {
        for(int i=0; i<6; ++i) {
            r[i] = 0;
        }
        b = 0;

        ac = 0;

        for(int i=0; i<N_ISSUE_HOT; ++i) {
            red_history_contrib[i] = 0;
        }
    }

public  :
    void    calcAC()
    {
        set<int>    dt;
        for (int i=0; i<6 - 1; ++i) {
            for (int j=i+1; j<6; ++j) {
                dt.insert( r[j] - r[i] );
            }
        }
        
        ac = dt.size() - ( 6 - 1 );
    }

    void    calcHotness( const Issue& issue_history ) 
    {
        int h_idx = id - issue_history.id - 1;
        if (h_idx >= N_ISSUE_HOT) {
            // too old, need not calculate
            return;
        }

        // TODO : to check if this history issue was calculated, before

        // build local
        set< int >  red_set;
        for ( int i=0; i<6; ++i ) {
            red_set.insert( r[i] );
        }

        // calculate hotness
        for ( int i=0; i<6; ++i ) {
            if ( red_set.count( issue_history.r[i] ) ) {
                int red_ball = issue_history.r[i];

                for (int i = h_idx; i < N_ISSUE_HOT; ++i ) {
                    red_history_contrib_set_iterator_type   it = red_history_contrib_set.find( i );
                    if ( it != red_history_contrib_set.end() ) {
                        set< int >& s = it->second;

                        s.insert( red_ball );
                    }
                    else {
                        set< int >  s;
                        s.insert( red_ball );

                        red_history_contrib_set.insert( make_pair(i, s) );
                    }
                }
            }
        }

        for ( int i=0; i < N_ISSUE_HOT; ++i ) {
            red_history_contrib_set_iterator_type   it = red_history_contrib_set.find( i );
            if ( it != red_history_contrib_set.end() ) {
                red_history_contrib[ i ] = static_cast< int >( it->second.size() );
            }
        }
    }
};



ostream&
operator<<( ostream& os, const Issue& issue )
{
    os << issue.date << " " << issue.id << " " 
       << setw(2) << setfill('0') << issue.r[0] << " " 
       << setw(2) << setfill('0') << issue.r[1] << " " 
       << setw(2) << setfill('0') << issue.r[2] << " " 
       << setw(2) << setfill('0') << issue.r[3] << " " 
       << setw(2) << setfill('0') << issue.r[4] << " " 
       << setw(2) << setfill('0') << issue.r[5] << "  "
       << setw(2) << setfill('0') << issue.b << "  "
       << "AC:" << issue.ac << " "
       << "C1:" << issue.red_history_contrib[0] << " "
       << "C2:" << issue.red_history_contrib[1] << " "
       << "C3:" << issue.red_history_contrib[2] << " "
       << "C4:" << issue.red_history_contrib[3] << " "
       << "C5:" << issue.red_history_contrib[4] << " "
       << endl;
}


///////////////////////////////////////////////////////////////////////
//


typedef vector<Issue>   issues_type;
typedef issues_type::iterator   issues_iterator_type;
issues_type issues;

void
loadDataFromFile(void)
{
    ifstream    ifs( g_text_filename );

    while( ! ifs.eof() ) {
        Issue   issue;

        ifs >> issue.date >> issue.id 
            >> issue.r[0] >> issue.r[1] >> issue.r[2] >> issue.r[3] >> issue.r[4] >> issue.r[5]
            >> issue.b;

        if ( ifs.eof() ) break;

        issues.push_back( issue );
    }

}


///////////////////////////////////////////////////////////////////////
//

typedef map<int, int>   blue_hot_type;
typedef blue_hot_type::iterator blue_hot_iterator_type;

void
calcBlueHotness(void)
{
    blue_hot_type   blue_hot;

    for ( int i=0; i<17; i++ ) {
        blue_hot.insert( make_pair( i, 0 ) );
    }

    for ( size_t i=0; i < issues.size(); ++i ) {
        Issue&  issue = issues[ i ];

        ++blue_hot[ issue.b ];
    }

    cout << "BLUE : " << setfill(' ');
    for (int i=1; i<17; i++) {
        cout << setw(4) << i;
    }
    cout << endl;
    cout << " HOT : ";
    for (int i=1; i<17; i++) {
        cout << setw(4) << blue_hot[i];
    }
    cout << endl;
}

void
calcBlueHotness32(void)
{
    blue_hot_type   blue_hot;

    for ( int i=0; i<17; i++ ) {
        blue_hot.insert( make_pair( i, 0 ) );
    }

    int total = static_cast< int >(issues.size());
    for ( int i = total - 1; (i >= 0) && (i >= (total - 32 - 1)); --i ) {
        Issue&  issue = issues[ i ];

        ++blue_hot[ issue.b ];
    }

    cout << "BL32 : " << setfill(' ');
    for (int i=1; i<17; i++) {
        cout << setw(4) << i;
    }
    cout << endl;
    cout << " H32 : ";
    for (int i=1; i<17; i++) {
        cout << setw(4) << blue_hot[i];
    }
    cout << endl;
}


///////////////////////////////////////////////////////////////////////
//


// calculate HOT and COLD balls in last 5 issue
void
calcHotColdBalls5()
{
    typedef map<int, int>   ball_type;
    typedef ball_type::iterator ball_iterator_type;

    ball_type   hot_balls, cold_balls;

    int N = 5;
    int latest_issue = issues.size() - 1;
    int lateN_issue = latest_issue - N;

    for( size_t k = latest_issue; k >= lateN_issue; --k ) {
        Issue&  issue_history = issues[k];

        for (int i=0; i<6; i++) {
            int red_ball = issue_history.r[i];

            ball_iterator_type  it = hot_balls.find( red_ball );
            if ( it == hot_balls.end() ) {
                hot_balls.insert( make_pair( red_ball, 1 ) );
            }
            else {
                int&    count = it->second;
                ++count;
            }
        }
    }

    for (int i=1; i<=33; i++) {
        if (hot_balls.count( i ) < 1) {
            cold_balls.insert( make_pair( i, 0 ) );
        }
    }

    // output :
    cout << "HOT  RED-BALL : ";
    ball_iterator_type  it_hot = hot_balls.begin();
    for( ; it_hot != hot_balls.end(); ++it_hot ) {
        cout << it_hot->first << "/" << it_hot->second << " ";
    }
    cout << endl;

    cout << "COLD RED-BALL : ";
    ball_iterator_type  it_cold = cold_balls.begin();
    for( ; it_cold != cold_balls.end(); ++it_cold ) {
        cout << it_cold->first << " ";
    }
    cout << endl;
}


void
guess(void)
{
    Issue   issue;

    issue.date = "2010-02-28";
    issue.id = 2010022;
    issue.r[0] = 3, 
    issue.r[1] = 10, 
    issue.r[2] = 15, 
    issue.r[3] = 18, 
    issue.r[4] = 21, 
    issue.r[5] = 29;
    issue.b = 14;

    issue.calcAC();

    for( size_t k = issues.size() - 1; k >= 0; ) {
        Issue&  issue_history = issues[k];
        
        issue.calcHotness( issue_history );

        if (k == 0) break;
        --k;
    }

    cout << "GUESS\n" << issue;
}


int main(void)
{

    loadDataFromFile();

    // do some calculating
    for( size_t i=0; i<issues.size(); ++i) {
        Issue&  issue = issues[i];

        issue.calcAC();

        if (i == 0) continue;
        for( size_t k = i - 1; k >= 0; ) {
            Issue&  issue_history = issues[k];
            
            issue.calcHotness( issue_history );

            if (k == 0) break;
            --k;
        }
    }

    // output 
    for( issues_iterator_type it = issues.begin(); it != issues.end(); ++it ) {
        Issue&  issue = *it;

        cout << issue;
    }

    // calculate blue hotness
    calcBlueHotness();
    calcBlueHotness32();

    // calculate HOT and COLD balls
    calcHotColdBalls5();

    // guess;
    guess();

    return  0;
}

